<?php
/**
 * 验证码短信发送类
 * User: dxk
 * Date: 2020/07/17
 */
namespace App\Library\Service;

use App\Library\Service\SMS\AliYun;
use App\Traits\SingleInstanceTrait;
use Carbon\Carbon;
use App\Service\EasyCache;

class SMSSend extends AliYun
{
    use SingleInstanceTrait;

    /**
     * 发送验证码
     * @param $mobile
     * @param $sms_tpl_code
     * @return array
     */
    public function sendCaptcha($mobile, $sms_tpl_code): array
    {
        $captcha = easy_random(6);
        $active_time = 180;
        //检测发送频率，防止短信轰炸
        $check_res = $this->checkMobileSendSpeed($sms_tpl_code, $mobile);
        if ($check_res !== true) {
            return alert_info(1, $check_res);
        }
        //发送短信
        $send_res = self::sendSMS($mobile, $sms_tpl_code, ['code' => $captcha]);
        if (isset($send_res['code']) && $send_res['code'] === 0) {
            $this->setMobileSendOk($sms_tpl_code, $mobile);
            $check_key = 'mobile_captcha:' . $sms_tpl_code . '_' . $mobile;
            // 设置短信验证码的有效时间
            $expires_at = Carbon::now()->addSeconds($active_time);
            EasyCache::getCache()->put($check_key, $captcha, $expires_at);
            $send_res['data']['captcha'] = $captcha;
            $send_res['data']['active_time'] = $active_time;
            $send_res['data']['expires_at'] = $expires_at;
            $mobile_tip = substr_replace($mobile, '****', 3, 4);
            $send_res['msg'] = '验证码已发送短信至手机' . $mobile_tip;
        }
        return $send_res;
    }

    /**
     * 验证验证码
     * @param $mobile
     * @param $sms_tpl_code
     * @param $user_captcha
     * @return bool
     */
    public function verifyCaptcha($mobile, $sms_tpl_code, $user_captcha): bool
    {
        return self::doVerifyCaptcha($sms_tpl_code, $mobile, $user_captcha);
    }

    /**
     * 检测手机号发送频率（同一个手机号间隔不低于30s，同一个手机号同一类型不低于60s,同一手机号每日不超过100）
     * @param $sms_tpl_code
     * @param $mobile
     * @return bool|string
     */
    private function checkMobileSendSpeed($sms_tpl_code, $mobile): bool|string
    {
        $key_prefix = 'mobile_msg:' . $mobile . ':';

        $key = $key_prefix . date('Ymd');
        $Cache = EasyCache::getCache();
        $day_count = (int)$Cache->get($key);
        if ($day_count > 100) {
            return '此手机号短信发送超出每日上限';
        }
        $key = $key_prefix . 'last_send_time';
        $last_send_time = (int)$Cache->get($key);
        if ((time() - $last_send_time) < 30) {
            return '发送频率太快了';
        }
        $key = $key_prefix . 'last_send_time' . $sms_tpl_code;
        $last_send_time = (int)$Cache->get($key);
        if ((time() - $last_send_time) < 60) {
            return '发送频率太快了';
        }
        return true;
    }

    /**
     * 短信发送频率基数
     * @param $sms_tpl_code
     * @param $mobile
     */
    private function setMobileSendOk($sms_tpl_code, $mobile): void
    {
        $key_prefix = 'mobile_msg:' . $mobile . ':';
        $expires_at = Carbon::now()->addDays();
        $key = $key_prefix . 'last_send_time';
        $Cache = EasyCache::getCache();
        $Cache->put($key, time(), $expires_at);

        $key = $key_prefix . 'last_send_time' . $sms_tpl_code;
        $Cache->put($key, time(), $expires_at);

        $key = $key_prefix . date('Ymd');
        $Cache->put($key, $Cache->get($key) + 1, $expires_at);
    }

    /**
     * 验证手机验证码是否正确
     * @param string $sms_tpl_code
     * @param string $mobile
     * @param string $user_captcha
     * @return boolean
     */
    private function doVerifyCaptcha(string $sms_tpl_code, string $mobile, string $user_captcha): bool
    {
        $mobile = trim($mobile);
        $check_key = 'mobile_captcha:' . $sms_tpl_code . '_' . $mobile;
        $user_captcha = trim($user_captcha);
        $captcha = EasyCache::getCache()->get($check_key);
        if (empty($user_captcha) || empty($mobile)) {
            return false;
        }
        EasyCache::getCache()->delete($check_key);
        if ($captcha != $user_captcha) {
            return false;
        }
        return true;
    }
}
